﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows;

using SBPweb.RIA.Shared.Contracts.Events;

using SBPweb.RIA.Client.Contracts.Base;
using SBPweb.RIA.Client.Contracts.Controllers;
using SBPweb.RIA.Client.Controls.Base;
using SBPweb.RIA.Client.Controls.Controllers;
using SBPweb.RIA.Client.Controls.Extensions;
using SBPweb.RIA.Client.Controls.Models;

using SBPweb.RIA.Client.Common.Collections;

using SBPweb.PROvibe.Client.Core.Models;
using SBPweb.PROvibe.Client.Core.Services.ContentContextProvider;

using SBPweb.PROvibe.Client.Library.Base;
using SBPweb.PROvibe.Client.Library.Controllers;
using SBPweb.PROvibe.Client.Library.Models;
using SBPweb.PROvibe.Client.Library.Modularity;

using SBPweb.PROvibe.Shared.Library.Components;
using SBPweb.PROvibe.Shared.Library.Layout;

namespace SBPweb.PROvibe.Client.Core.Controllers
{
    
    public class ContentContextController : ControllerBase<IContentContextModel, ContentContextModel, IContentContextController>, IContentContextController
    {

        #region Fields

        private ContentContextProviderServiceClient serviceClient = new ContentContextProviderServiceClient();

        #endregion

        #region Constructor logic

        public ContentContextController()
        {
            Model = new ContentContextModel();

            serviceClient.FixEndpointAddress<IContentContextProviderService>("services/dynamic");

            model.PendingModulesStarted += new EventHandler(model_PendingModulesStarted);
            model.PendingModulesFinished += new EventHandler(model_PendingModulesFinished);

            ManagableReadOnlyObservableList<IModule> ms = new ManagableReadOnlyObservableList<IModule>();
            ManagableReadOnlyObservableList<IService> ss = new ManagableReadOnlyObservableList<IService>();
            ms.ManagableItems.CollectionChanged += new NotifyCollectionChangedEventHandler(Modules_ManagableItems_CollectionChanged);
            ss.ManagableItems.CollectionChanged += new NotifyCollectionChangedEventHandler(Services_ManagableItems_CollectionChanged);
            model.Modules = ms;
            model.Services = ss;

            serviceClient.GetCurrentPageContextCompleted += new EventHandler<GetCurrentPageContextCompletedEventArgs>(serviceClient_GetCurrentPageContextCompleted);
        }

        ~ContentContextController()
        {
            //ExtendableApplication.Current.MainWindow.Dispatcher.BeginInvoke(() =>
            //{
            //    ManagableReadOnlyObservableList<IModule> ms = model.Modules as ManagableReadOnlyObservableList<IModule>;
            //    ManagableReadOnlyObservableList<IService> ss = model.Services as ManagableReadOnlyObservableList<IService>;
            //    if (ms != null)
            //    {
            //        ms.ManagableItems.CollectionChanged -= new NotifyCollectionChangedEventHandler(Modules_ManagableItems_CollectionChanged);
            //    }
            //    if (ss != null)
            //    {
            //        ss.ManagableItems.CollectionChanged -= new NotifyCollectionChangedEventHandler(Services_ManagableItems_CollectionChanged);
            //    }
            //    serviceClient.GetCurrentPageContextCompleted -= new EventHandler<GetCurrentPageContextCompletedEventArgs>(serviceClient_GetCurrentPageContextCompleted);
            //});
        }

        #endregion

        #region Properties

        internal ContentContextModel model
        {
            get
            {
                return Model as ContentContextModel;
            }
        }

        #endregion

        #region Methods

        public static void RegisterApplicationSingleton()
        {
            RegisterController(new ContentContextController());
        }

        public void GetCurrentPageContext()
        {
            string path = ExtendableApplication.Current.HostBaseUri.OriginalString;
            string layout = BrowserModel.GetQueryParameter("layout");
            string pageId = BrowserModel.GetQueryParameter("pageId");
            if (!string.IsNullOrEmpty(layout))
            {
                model.Layout = (LayoutModes)Enum.Parse(typeof(LayoutModes), layout, true);
            }
            serviceClient.GetCurrentPageContextAsync(path);
        }

        public T GetService<T>() where T : IService
        {
            return model.Services.FirstByType<T>();
        }

        public T GetService<T>(string serviceName) where T : IService
        {
            return model.Services.FirstByName<T>(serviceName);
        }

        public void RegisterService<T>(T service) where T : IService
        {
            ManagableReadOnlyObservableList<IService> mrooc = model.Services as ManagableReadOnlyObservableList<IService>;
            mrooc.ManagableItems.Add(service);
        }

        #endregion

        #region Event handlers

        private void serviceClient_GetCurrentPageContextCompleted(object sender, GetCurrentPageContextCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                throw e.Error;
            }

            lock (this)
            {
                model.Application = e.Result.Application;
                Page page = e.Result.Page;
                model.Page = page;
                page.Parent = model.Application;
                page.Zones = new ReadOnlyCollection<IZone>(e.Result.Zones.Cast<IZone>().ToList());

                model.EnqueuePendingModules(e.Result.Modules.Cast<IModule>());
                foreach (IModule module in e.Result.Modules)
                {
                    AsyncRequestArgs<IList<Assembly>> ara = new AsyncRequestArgs<IList<Assembly>>(new AsyncRequestHandler<IList<Assembly>>(LoadPackageCompleted), module);
                    PackageLoaderController.Controller.LoadPackage(module.Path, ara);
                }
            }
        }
        
        private void LoadPackageCompleted(object sender, GenericEventArgs<IList<Assembly>> e)
        {
            AsyncRequestArgs<IList<Assembly>> ara = e as AsyncRequestArgs<IList<Assembly>>;
            Assembly asm = e.Result.FirstOrDefault();
            Type type = typeof(IModule);
            Type moduleType = asm.GetTypes().FirstOrDefault(x => type.IsAssignableFrom(x));
            if (moduleType != null)
            {
                IModule module = ara.Arguments.FirstOrDefault().Value as IModule;
                ClientModuleBase clientModule = Activator.CreateInstance(moduleType, module) as ClientModuleBase;
                ManagableReadOnlyObservableList<IModule> modules = model.Modules as ManagableReadOnlyObservableList<IModule>;
                modules.ManagableItems.Add(clientModule);
                model.DequeuePendingModule(module);
            }
        }

        private void model_PendingModulesStarted(object sender, EventArgs e)
        {
        }

        private void model_PendingModulesFinished(object sender, EventArgs e)
        {
            foreach (ClientModuleBase module in model.Modules)
            {
                module.Initialize();
            }
        }

        private void Modules_ManagableItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            ObservableList<IModule> modules = sender as ObservableList<IModule>;
            modules.Sort();
        }

        private void Services_ManagableItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            ObservableList<IService> services = sender as ObservableList<IService>;
            services.Sort();
        }

        #endregion

    }

}